﻿using ETW.EventListeners.ObjectValues;

namespace ETW.EventListeners.Listeners
{
    /// <summary>
    /// 主机事件监听
    /// Microsoft.AspNetCore.Hosting
    /// <para>
    /// 该监听器中的计数器作为 ASP.NET Core 的一部分发布，并在 HostingEventSource.cs 中进行维护。
    /// </para>
    /// <para>https://docs.microsoft.com/zh-cn/dotnet/core/diagnostics/available-counters#microsoftaspnetcorehosting-counters</para>
    /// </summary>
    public class HostingEventListener: EventListener
    {

        #region 事件
        /// <summary>
        /// 当写入已启动但尚未停止的请求总数时触发
        /// <para>Current Requests (current-requests)</para>
        /// </summary>
        public event Action<MeanCounterPayload, EventWrittenEventArgs> OnCurrentRequestsWritten;
        /// <summary>
        /// 当写入应用生命周期内发生的失败请求总数时触发
        /// <para>Failed Requests (failed-requests)</para>
        /// </summary>
        public event Action<MeanCounterPayload, EventWrittenEventArgs> OnFailedRequestsWritten;
        /// <summary>
        /// 当写入每个更新间隔发生的请求数时触发
        /// <para>Request Rate (requests-per-second)</para>
        /// </summary>
        public event Action<SumCounterPayload, EventWrittenEventArgs> OnRequestRateWritten;
        /// <summary>
        /// 当写入应用生命周期内发生的请求总数时触发
        /// <para>Total Requests (total-requests)</para>
        /// </summary>
        public event Action<MeanCounterPayload, EventWrittenEventArgs> OnTotalRequestsWritten;
        #endregion

        public HostingEventListener() { }

        protected override void OnEventSourceCreated(EventSource eventSource)
        {
            if (!eventSource.Name.Equals("Microsoft.AspNetCore.Hosting")) return;

            // 启用时间，并设置事件等级、事件关键字及事件计数器间隔时间(单位秒)
            EnableEvents(eventSource, DefaultConfiguration.HostingEventListenerOptions.EventLevel, DefaultConfiguration.HostingEventListenerOptions.EventKeywords, new Dictionary<string, string> { ["EventCounterIntervalSec"] = DefaultConfiguration.HostingEventListenerOptions.EventCounterIntervalSec.ToString() });
        }

        protected override void OnEventWritten(EventWrittenEventArgs eventData)
        {
            if (!"EventCounters".Equals(eventData.EventName)) return;
            if (!"Microsoft.AspNetCore.Hosting".Equals(eventData.EventSource.Name)) return;

            for (var i = 0; i < eventData.Payload.Count; i++)
            {
                if (eventData.Payload[i] is IDictionary<string, object> eventPayload)
                {
                    var counterName = GetName(eventPayload);

                    MeanCounterPayload meanCounterPayload = null;
                    SumCounterPayload sumCounterPayload = null;
                    var CounterType = eventPayload["CounterType"].ToString();

                    if (CounterType.Equals("Mean"))
                        meanCounterPayload = MeanCounterPayload.ConvertFrom(eventPayload);
                    else if (CounterType.Equals("Sum"))
                        sumCounterPayload = SumCounterPayload.ConvertFrom(eventPayload);
                    else continue;

                    switch (counterName)
                    {
                        case "current-requests":
                            if (OnCurrentRequestsWritten != null)
                                OnCurrentRequestsWritten.Invoke(meanCounterPayload, eventData);
                            //Task.Factory.StartNew(() => { 
                            //    OnCurrentRequestsWritten.Invoke(meanCounterPayload, eventData); 
                            //});
                            break;
                        case "failed-requests":
                            if (OnFailedRequestsWritten != null)
                                OnFailedRequestsWritten.Invoke(meanCounterPayload, eventData);
                            //Task.Factory.StartNew(() => { OnFailedRequestsWritten.Invoke(meanCounterPayload, eventData); });
                            break;
                        case "requests-per-second":
                            if (OnRequestRateWritten != null)
                                OnRequestRateWritten.Invoke(sumCounterPayload, eventData);
                            //Task.Factory.StartNew(() => { OnRequestRateWritten.Invoke(sumCounterPayload, eventData); });
                            break;
                        case "total-requests":
                            if (OnTotalRequestsWritten != null)
                                OnTotalRequestsWritten.Invoke(meanCounterPayload, eventData);
                            //Task.Factory.StartNew(() => { OnTotalRequestsWritten.Invoke(meanCounterPayload, eventData); });
                            break;
                    }
                }
            }
        }
        private static string GetName(IDictionary<string, object> eventPayload)
        {
            var counterName = "";
            if (eventPayload.TryGetValue("Name", out object displayValue))
            {
                counterName = displayValue.ToString();
            }

            return counterName;
        }
    }
}
